#include "MaterialGraphPinViewModel.h"

#include "MaterialGraph/MaterialGraphViewModel.h"
#include "MaterialGraph/Node/MaterialGraphNodeViewModel.h"
#include "Framework/Editor.h"
#include "Theme/EditorTheme.h"
#include "MaterialGraphPinModel.h"


void RMaterialGraphPinViewModel::BindModel(TSharedObjectPtr<RMaterialGraphPinModel> InModel, TSharedObjectPtr<RMaterialGraphNodeViewModel> InNode)
{
    BaseModel=InModel;
    BaseNode=InNode;

    BaseModel->OnLinkChanged.Bind([this]()
    {
        this->OnLinkChanged.ExecuteIfBound();
    });

    switch (BaseModel->ValueType)
    {
    case EMaterialGraphValueType::Vector1D:
        PinColor = REditor::Get()->CurrentTheme->Vector1DPinColor;
        break;
    case EMaterialGraphValueType::Vector2D:
        PinColor = REditor::Get()->CurrentTheme->Vector2DPinColor;
        break;
    case EMaterialGraphValueType::Vector3D:
        PinColor = REditor::Get()->CurrentTheme->Vector3DPinColor;
        break;
    case EMaterialGraphValueType::Vector4D:
        PinColor = REditor::Get()->CurrentTheme->Vector4DPinColor;
        break;
    default:
        assert(false);
        break;
    }
}

void RMaterialGraphPinViewModel::SetLineIndex(int64_t InIndex)
{
    LineIndex = InIndex;
}

int64_t RMaterialGraphPinViewModel::GetLineIndex() const
{
    return LineIndex;
}

float RMaterialGraphPinViewModel::GetCenterXInNodeWidget()
{
    if(IsOutput())
    {
        return BaseNode->GetNodeWidth();
    }
    else
    {
        return 0;
    }
}

float RMaterialGraphPinViewModel::GetCenterYInNodeWidget()
{
    return BaseNode->GetLineY(LineIndex) + BaseNode->LineHeight*0.5f;
}

float RMaterialGraphPinViewModel::GetCenterXInGraphWidget()
{
    float offsetX = 
        BaseNode->GetGraphOffset().X 
        + BaseNode->GetNodeX()
        + GetCenterXInNodeWidget();
    return offsetX * BaseNode->GetScale();
}

float RMaterialGraphPinViewModel::GetCenterYInGraphWidget()
{
    float offset=
        BaseNode->GetGraphOffset().Y 
        +BaseNode->GetNodeY()
        +GetCenterYInNodeWidget();
    return offset * BaseNode->GetScale();
}

void RMaterialGraphPinViewModel::OnDragStarted()
{
    BaseNode->OnPinDragStarted(this);
}

void RMaterialGraphPinViewModel::OnDragEnded()
{
    BaseNode->OnPinDragEnded(this);
}

float RMaterialGraphPinViewModel::GetLineHeight() const
{
    return BaseNode->LineHeight;
}

SColor RMaterialGraphPinViewModel::GetPinColor() const
{
    return PinColor;
}

bool RMaterialGraphPinViewModel::IsOutput() const
{
    return BaseModel->bIsOutput;
}

bool RMaterialGraphPinViewModel::IsHidden() const
{
    return BaseModel->bIsHidden;
}

float RMaterialGraphPinViewModel::GetDefaultX() const
{
    return BaseModel->DefaultInputX;
}

void RMaterialGraphPinViewModel::SetDefaultX(float InValue)
{
auto ChangePropertyOperation=NewObject<RMaterialChangeObjectPropertyOperation>();
    ChangePropertyOperation->
        SetObjectAndOffset(
            BaseModel
            ,offsetof(RMaterialGraphPinModel,DefaultInputX)
        );
    ChangePropertyOperation->OldValue=BaseModel->DefaultInputX;
    ChangePropertyOperation->NewValue=InValue;
    ChangePropertyOperation->bCanCombine=true;

    BaseNode->GetGraphViewModel()->RedoOperation(ChangePropertyOperation);
    BaseNode->GetGraphViewModel()->AddOperation(ChangePropertyOperation);

}

float RMaterialGraphPinViewModel::GetDefaultY() const
{
    return BaseModel->DefaultInputY;
}

void RMaterialGraphPinViewModel::SetDefaultY(float InValue)
{
    auto ChangePropertyOperation=NewObject<RMaterialChangeObjectPropertyOperation>();
    ChangePropertyOperation->
        SetObjectAndOffset(
            BaseModel
            ,offsetof(RMaterialGraphPinModel,DefaultInputY)
        );
    ChangePropertyOperation->OldValue=BaseModel->DefaultInputY;
    ChangePropertyOperation->NewValue=InValue;
    ChangePropertyOperation->bCanCombine=true;

    BaseNode->GetGraphViewModel()->RedoOperation(ChangePropertyOperation);
    BaseNode->GetGraphViewModel()->AddOperation(ChangePropertyOperation);
}

float RMaterialGraphPinViewModel::GetDefaultZ() const
{
    return BaseModel->DefaultInputZ;
}

void RMaterialGraphPinViewModel::SetDefaultZ(float InValue)
{
    auto ChangePropertyOperation=NewObject<RMaterialChangeObjectPropertyOperation>();
    ChangePropertyOperation->
        SetObjectAndOffset(
            BaseModel
            ,offsetof(RMaterialGraphPinModel,DefaultInputZ)
        );
    ChangePropertyOperation->OldValue=BaseModel->DefaultInputZ;
    ChangePropertyOperation->NewValue=InValue;
    ChangePropertyOperation->bCanCombine=true;

    BaseNode->GetGraphViewModel()->RedoOperation(ChangePropertyOperation);
    BaseNode->GetGraphViewModel()->AddOperation(ChangePropertyOperation);
}

SVec4 RMaterialGraphPinViewModel::GetDefaultXYZW() const
{
    return SVec4(
        BaseModel->DefaultInputX
        ,BaseModel->DefaultInputY
        ,BaseModel->DefaultInputZ
        ,BaseModel->DefaultInputW
    );
}


TSharedObjectPtr<RMaterialGraphPinModel> RMaterialGraphPinViewModel::GetModel() const
{
    return BaseModel;
}

TSharedObjectPtr<RMaterialGraphNodeViewModel> RMaterialGraphPinViewModel::GetNodeViewModel()
{
    return BaseNode;
}

bool RMaterialGraphPinViewModel::HasValidLink() const
{
    return BaseModel->HasValidLink();
}

